package com.ruixun.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruixun.common.ResponseResult;
import com.ruixun.entity.User;
import com.ruixun.mapper.UserMapper;
import com.ruixun.service.RedisService;
import com.ruixun.utils.JwtUtils;
import com.ruixun.vo.LoginVo;
import com.ruixun.vo.RegisterVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 认证控制器
 * @author ruixun
 */
@Api(tags = "认证接口")
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Slf4j
public class AuthController {

    private final AuthenticationManager authenticationManager;
    private final JwtUtils jwtUtils;
    private final RedisService redisService;
    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;

    @ApiOperation(value = "用户登录", notes = "用户登录接口")
    @PostMapping("/login")
    public ResponseResult<Map<String, Object>> login(@Valid @RequestBody LoginVo loginVo) {
        try {
            // 验证用户
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginVo.getUsername(),
                            loginVo.getPassword()
                    )
            );

            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 生成JWT令牌
            String token = jwtUtils.generateToken((org.springframework.security.core.userdetails.User) authentication.getPrincipal());

            // 存储token到Redis
            String redisKey = "auth:token:" + loginVo.getUsername();
            redisService.storeToken(redisKey, token, 1, TimeUnit.DAYS);

            // 获取用户信息
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(User::getLoginName, loginVo.getUsername())
                      .eq(User::getStatus, 1)
                      .eq(User::getDeleted, 0);
            User user = userMapper.selectOne(userWrapper);

            // 构建返回数据
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("user", user);
            result.put("msgTip", "user can login");

            log.info("用户登录成功: {}", loginVo.getUsername());
            return ResponseResult.success(result);

        } catch (Exception e) {
            log.error("用户登录失败: {}", e.getMessage());
            return ResponseResult.fail("用户名或密码错误");
        }
    }

    @ApiOperation(value = "用户注册", notes = "用户注册接口")
    @PostMapping("/register")
    public ResponseResult<String> register(@Valid @RequestBody RegisterVo registerVo) {
        try {
            // 检查用户名是否已存在
            LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(User::getLoginName, registerVo.getUsername())
                      .eq(User::getDeleted, 0);

            if (userMapper.selectCount(userWrapper) > 0) {
                return ResponseResult.fail("用户名已存在");
            }

            // 创建新用户
            User user = new User();
            user.setLoginName(registerVo.getUsername());
            user.setUserName(registerVo.getUsername());
            user.setPassword(passwordEncoder.encode(registerVo.getPassword()));
            user.setStatus(1);
            user.setDeleted(0);
            user.setIsmanager("0");


            userMapper.insert(user);

            log.info("用户注册成功: {}", registerVo.getUsername());
            return ResponseResult.success("注册成功");

        } catch (Exception e) {
            log.error("用户注册失败: {}", e.getMessage());
            return ResponseResult.fail("注册失败");
        }
    }

    @ApiOperation(value = "用户登出", notes = "用户登出接口")
    @PostMapping("/logout")
    public ResponseResult<String> logout(@RequestHeader("Authorization") String token) {
        try {
            if (token != null && token.startsWith("Bearer ")) {
                String jwtToken = token.substring(7);
                String username = jwtUtils.getUsernameFromToken(jwtToken);

                // 从Redis中删除token
                String redisKey = "auth:token:" + username;
                redisService.deleteToken(redisKey);

                log.info("用户登出成功: {}", username);
            }

            return ResponseResult.success("登出成功");
        } catch (Exception e) {
            log.error("用户登出失败: {}", e.getMessage());
            return ResponseResult.fail("登出失败");
        }
    }

    @ApiOperation(value = "刷新token", notes = "刷新token接口")
    @PostMapping("/refresh")
    public ResponseResult<Map<String, Object>> refresh(@RequestHeader("Authorization") String token) {
        try {
            if (token != null && token.startsWith("Bearer ")) {
                String jwtToken = token.substring(7);
                String username = jwtUtils.getUsernameFromToken(jwtToken);

                // 检查Redis中是否存在该token
                String redisKey = "auth:token:" + username;
                if (!redisService.hasToken(redisKey)) {
                    return ResponseResult.fail("token已过期");
                }

                // 刷新token
                String newToken = jwtUtils.refreshToken(jwtToken);

                // 更新Redis中的token
                redisService.storeToken(redisKey, newToken, 1, TimeUnit.DAYS);

                Map<String, Object> result = new HashMap<>();
                result.put("token", newToken);

                return ResponseResult.success(result);
            }

            return ResponseResult.fail("无效的token");
        } catch (Exception e) {
            log.error("刷新token失败: {}", e.getMessage());
            return ResponseResult.fail("刷新token失败");
        }
    }
}